/*
 * Created by SharpDevelop.
 * User: MyWife
 * Date: 7/12/2009
 * Time: 11:11 PM
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.IO;
using System.Text;
using Microsoft.Win32;
using System.Windows.Forms;

namespace popLib
{
	/// <summary>
	/// Description of ProfileLib.
	/// </summary>
	public class ProfileLib
	{
		public enum ProfileType{ Xml, Registry, Ini, Config }
		
			
		public static Profile initProfile( ProfileType type, string profilePath ){
			Profile profile;
			switch( type ){				
				case ProfileType.Config: profile = new Config(profilePath); break;
				case ProfileType.Registry: profile = new PRegistry(profilePath); break;
				case ProfileType.Xml: profile = new Xml(profilePath); break;
				case ProfileType.Ini:
				default: profile = new Ini(profilePath); break;
			}
			return profile;
		}	
	}
	
	public class Config:Profile{
		public Config(string profilePath):base(profilePath){}
		
		public override string[] getKeyNames(string section){
			return null;
		}
		public override string[] getSectionNames(){
			return null;
		}
		
		public override string getValue(string section, string key){
			return null;
		}
		public override void setValue(string section, string key, string value){
			
		}
		
		public override void removeKey(string section, string key){
			
		}
		public override void removeSection(string section){
			
		}
	}
	
	public class PRegistry:Profile{
		
		private RegistryKey m_rootKey = Microsoft.Win32.Registry.CurrentUser;
		
		public PRegistry(string profilePath ):base(profilePath){
			if( !StringLib.isValid( profilePath ) )				
				this.ProfilePath = "Software\\" + Application.CompanyName + "\\" + Application.ProductName;
		}
		
		public PRegistry(){
			this.ProfilePath = "Software\\" + Application.CompanyName + "\\" + Application.ProductName;
		}
		public PRegistry(RegistryKey rootKey, string subKeyName){
			
			if (rootKey != null)
				m_rootKey = rootKey;
			if (subKeyName != null)
				this.ProfilePath = subKeyName;
			else this.ProfilePath = "Software\\" + Application.CompanyName + "\\" + Application.ProductName;
		}
		
		public override string[] getKeyNames(string section){
			return null;
		}
		public override string[] getSectionNames(){
			return null;
		}
		
		public override string getValue(string section, string key){
			using (RegistryKey subKey = GetSubKey(section, false, false))
				return (subKey == null ? null : subKey.GetValue(key).ToString());
		}
		public override void setValue(string section, string key, string value){
			// If the value is null, remove the entry
			if (value == null)
			{
				removeKey(section, key);
				return;
			}
			
			using (RegistryKey subKey = GetSubKey(section, true, true))
				subKey.SetValue(key, value);
		}
		
		public override void removeKey(string section, string key){
			using (RegistryKey subKey = GetSubKey(section, false, true))
			{
				if (subKey != null && subKey.GetValue(key) != null)
				{					
					subKey.DeleteValue(key, false);
				}
			}	
		}
		public override void removeSection(string section){
			using (RegistryKey key = m_rootKey.OpenSubKey(ProfilePath, true))
			{
				if (key != null && isSectionExist(section))
				{
					key.DeleteSubKeyTree(section);
				}
			}
		}
		
		protected RegistryKey GetSubKey(string section, bool create, bool writable)		
		{
			string keyName = ProfilePath + "\\" + section;

			if (create)
				return m_rootKey.CreateSubKey(keyName);
			return m_rootKey.OpenSubKey(keyName, writable);
		}
	}
	
	public class Xml:Profile{
		public Xml(string ProfilePath){
		}
		
		
		public override string[] getKeyNames(string section){
			return null;
		}
		public override string[] getSectionNames(){
			return null;
		}
		
		public override string getValue(string section, string key){
			return null;
		}
		public override void setValue(string section, string key, string value){
			
		}
		
		public override void removeKey(string section, string key){
			
		}
		public override void removeSection(string section){
			
		}
	}
	
	public class Ini:Profile{
		
		public Ini(string profilePath):base(profilePath){}
		
		public override string[] getKeyNames(string section){
			// Verify the section exists
			if (!isSectionExist(section)) return null;
			
			// Loop until the buffer has grown enough to fit the value
			for (int maxSize = 500; true; maxSize *= 2)
			{
				byte[] bytes = new byte[maxSize];				
            	int size = APILib.GetPrivateProfileStringW(section, 0, "", bytes, maxSize, ProfilePath);
				
				if (size < maxSize - 2)
				{
					// Convert the buffer to a string and split it
					string entries = Encoding.UTF8.GetString(bytes, 0, size - (size > 0 ? 1 : 0));			
					if (entries == "")
						return new string[0];
		            return entries.Split(new char[] {'\0'});			
				}
			}
		}
		public override string[] getSectionNames(){
			// Verify the file exists
			if (!File.Exists(this.ProfilePath)) return null;
			
			// Loop until the buffer has grown enough to fit the value
			for (int maxSize = 500; true; maxSize *= 2)
			{
				byte[] bytes = new byte[maxSize];				
            	int size = APILib.GetPrivateProfileStringW(0, "", "", bytes, maxSize, ProfilePath);
				
				if (size < maxSize - 2)
				{
					// Convert the buffer to a string and split it
					string sections = Encoding.UTF8.GetString(bytes, 0, size - (size > 0 ? 1 : 0));			
					if (sections == "")
						return new string[0];
		            return sections.Split(new char[] {'\0'});			
				}
			}
		}
		
		public override string getValue(string section, string key){
			// Loop until the buffer has grown enough to fit the value
			for (int maxSize = 250; true; maxSize *= 2)
			{
				StringBuilder result = new StringBuilder(maxSize);
            	int size = APILib.GetPrivateProfileStringW(section, key, "", result, maxSize, ProfilePath);
				
				if (size < maxSize - 1)
				{					
					if (size == 0 && !isKeyExist(section, key))
						return null;
					return result.ToString();
				}
			}
		}
		public override void setValue(string section, string key, string value){
			// If the value is null, remove the entry
			if (value == null)
			{
				removeKey(section, key);
				return;
			}
			
			APILib.WritePrivateProfileStringW(section, key, value.ToString(), ProfilePath);
		}
		
		public override void removeKey(string section, string key){
			// Verify the entry exists
			if (!isKeyExist(section, key)) return;			
			APILib.WritePrivateProfileStringW(section, key, 0, ProfilePath);
		}
		public override void removeSection(string section){
			// Verify the section exists
			if (!isSectionExist(section)) return;			
			APILib.WritePrivateProfileStringW(section, 0, "", ProfilePath);
		}        
	}
	
	public abstract class Profile:IProfile{
		
		public Profile( string profilePath ){
			this.file = profilePath;
		}
		
		public Profile(){}
		
		string file;
		public string ProfilePath{
			get{ return file; } 
			set{ this.file = value;}
		}
		public abstract string[] getKeyNames(string section);
		public abstract string[] getSectionNames();
		public bool isKeyExist(string section, string key){
			string[] entries = getKeyNames(section);
			
			if (entries == null) return false;

			return Array.IndexOf(entries, key) >= 0;
		}
		public bool isSectionExist(string section){
			string[] sections = getSectionNames();

			if (sections == null)return false;

			return Array.IndexOf(sections, section) >= 0;
		}
		
		public string getValue(string section, string key, string defaultValue){
			try{
        		string result = getValue(section, key);
        		
        		if( !StringLib.isValid(result) ){
        			setValue(section, key, defaultValue);
        			return defaultValue;
        		}
        		
        		return result;
        	}catch{
        		setValue(section, key, defaultValue);
        		return defaultValue;
        	}
		}
		
		public bool getBoolean( string section, string key, bool defaultValue ){
        	string result = getValue( section, key, defaultValue ? "1" : "0" );
        	
        	if( result != "1" && result != "0" ){
        		setValue(section, key, defaultValue ? "1" : "0");
        		return defaultValue;
        	}
        	
        	return result == "1" ? true : false;
        }
		
		public void setBoolean( string section, string key, bool value ){
			setValue( section, key, value ? "1" : "0" );
		}
        
        public int getInt( string section, string key, int defaultValue ){
        	string result = getValue( section, key, defaultValue.ToString() );
        	return NumberLib.getInt( result );
        }
        
        public double getDouble( string section, string key, double defaultValue ){
        	string result = getValue( section, key, defaultValue.ToString() );
        	return NumberLib.getDouble( result );
        }
		
		public abstract string getValue(string section, string key);
		public abstract void setValue(string section, string key, string value);
		public abstract void removeKey(string section, string key);
		public abstract void removeSection(string section);
	}
	
	public interface IProfile
	{
		string ProfilePath{get;set;}
		string[] getKeyNames(string section);
		string[] getSectionNames();
		bool isKeyExist(string section, string key);
		bool isSectionExist(string section);
		
		string getValue(string section, string key);
		string getValue(string section, string key, string defaultValue);
		bool getBoolean( string section, string key, bool defaultValue );
		int getInt( string section, string key, int defaultValue );
		double getDouble( string section, string key, double defaultValue );
		
		void setValue(string section, string key, string value);
		
	}
}
